#include "include.h"
#include "bsp_dac.h"

typedef struct {
	u8 eq_en;
	u8 eq_num;
	u8 eq_rfu[2];
	u8 *eq_coef;

	u8 drc_en;
	u8 drc_type;
	u8 drc_rfu[2];
	u8 *drc_coef;
} eq_drc_cfg_t;
#define SCO_VOL_OFFSET 3
const u8  *dac_avol_table;
const u16 *dac_dvol_table;

//PE7 翻转会干扰DAC输出。
//若程序中有PE7在不断翻转(如用于推屏等)，该函数需要返回1，优化该干扰。
AT(.text.dac.patch)
u8 pe7_turn_optimize(void)
{
    return 0;
}

AT(.text.bsp.dac.table)
const u8 dac_vol_tbl_16[16 + 1] = {
    //取值范围：(54-54) ~ (54+5),共60个值;
    //说明：值(54-54)对应音量-54dB; 54对应音量0dB;
    54-54, 54-43, 54-32, 54-26, 54-22, 54-18, 54-15, 54-12,
    54-10, 54-8,  54-6,  54-4,  54-3,  54-2,  54-1,  54,  54+1
};

AT(.text.bsp.dac.table)
const u8 dac_vol_tbl_32[32 + 1] = {
    //取值范围：(54-54) ~ (54+5),共60个值;
    //说明：值(54-54)对应音量-54dB; 54对应音量0dB;
    54-54, 54-43, 54-38, 54-35, 54-32, 54-30, 54-28, 54-26,
    54-24, 54-22, 54-21, 54-20, 54-19, 54-18, 54-17, 54-16,
    54-15, 54-14, 54-13, 54-12, 54-11, 54-10, 54-9,  54-8,
    54-7,  54-6,  54-5,  54-4,  54-3,  54-2,  54-1,  54,
    54+1,
};

AT(.text.bsp.dac.table)
const u8 dac_vol_tbl_50[50 + 1] = {
    //取值范围：(54-54) ~ (54+5),共60个值;
    //说明：值(54-54)对应音量-54dB; 54对应音量0dB;
    54-54, 54-43, 54-39, 54-38, 54-37, 54-36, 54-35, 54-34,
    54-33, 54-32, 54-31, 54-30, 54-29, 54-28, 54-27, 54-26,
    54-25, 54-24, 54-23, 54-22, 54-21, 54-20, 54-19, 54-18,
    54-17, 54-16, 54-15, 54-14, 54-13, 54-12, 54-11, 54-10,
    54-9,  54-8,  54-7,  54-6,  54-6,  54-5,  54-5,  54-4,
    54-4,  54-3,  54-3,  54-2,  54-2,  54-1,  54-1,  54,
    54,    54+1,  54+1,
};

#if DAC_DRC_EN || DAC_SOFT_EQ_EN
static eq_drc_cfg_t drc_cfg = {
    .eq_en = DAC_SOFT_EQ_EN,
    .eq_num = 6,
    .eq_coef = NULL,    //初始化时定义

    .drc_en = DAC_DRC_EN,
    .drc_type = 0,      //0: (L+R) / 2运算； 1： L、R独立运算
    .drc_coef = NULL,
};
#endif

AT(.text.bsp.dac.table)
const u16 dac_dvol_tbl_16[16 + 1] = {
    DIG_N60DB,  DIG_N43DB,  DIG_N32DB,  DIG_N26DB,  DIG_N24DB,  DIG_N22DB,  DIG_N20DB,  DIG_N18DB, DIG_N16DB,
    DIG_N14DB,  DIG_N12DB,  DIG_N10DB,  DIG_N8DB,   DIG_N6DB,   DIG_N4DB,   DIG_N2DB,   DIG_N0DB,
};

AT(.text.bsp.dac.table)
const u16 dac_dvol_tbl_32[32 + 1] = {
    DIG_N60DB,  DIG_N50DB,  DIG_N43DB,  DIG_N38DB,  DIG_N35DB,  DIG_N30DB,  DIG_N28DB,  DIG_N26DB,
    DIG_N24DB,  DIG_N22DB,  DIG_N21DB,  DIG_N20DB,  DIG_N19DB,  DIG_N18DB,  DIG_N17DB,  DIG_N16DB,
    DIG_N16DB,  DIG_N15DB,  DIG_N14DB,  DIG_N13DB,  DIG_N12DB,  DIG_N11DB,  DIG_N10DB,  DIG_N9DB,
    DIG_N8DB,   DIG_N7DB,   DIG_N6DB,   DIG_N5DB,   DIG_N4DB,   DIG_N3DB,   DIG_N2DB,   DIG_N1DB,   DIG_N0DB,
};

AT(.text.bsp.dac.table)
const u16 dac_dvol_tbl_50[50 + 1] = {
    DIG_N60DB,  DIG_N56DB,  DIG_N52DB,  DIG_N48DB,  DIG_N44DB,  DIG_N42DB,  DIG_N40DB,  DIG_N38DB,
    DIG_N37DB,  DIG_N36DB,  DIG_N35DB,  DIG_N34DB,  DIG_N33DB,  DIG_N32DB,  DIG_N31DB,  DIG_N30DB,
    DIG_N29DB,  DIG_N28DB,  DIG_N28DB,  DIG_N27DB,  DIG_N26DB,  DIG_N25DB,  DIG_N25DB,  DIG_N24DB,
    DIG_N23DB,  DIG_N22DB,  DIG_N21DB,  DIG_N20DB,  DIG_N20DB,  DIG_N19DB,  DIG_N18DB,  DIG_N18DB,
    DIG_N17DB,  DIG_N16DB,  DIG_N16DB,  DIG_N15DB,  DIG_N14DB,  DIG_N13DB,  DIG_N12DB,  DIG_N11DB,
    DIG_N10DB,  DIG_N9DB,   DIG_N8DB,   DIG_N7DB,   DIG_N6DB,   DIG_N5DB,   DIG_N4DB,   DIG_N3DB,
    DIG_N2DB,   DIG_N1DB,   DIG_N0DB,
};

AT(.text.bsp.aucar.table)
const u16 aucar_bal_vol_table[16 + 1] = {
    DIG_N60DB,  DIG_N43DB,  DIG_N32DB,  DIG_N26DB,  DIG_N24DB,  DIG_N22DB,  DIG_N20DB,  DIG_N18DB, DIG_N16DB,
    DIG_N14DB,  DIG_N12DB,  DIG_N10DB,  DIG_N8DB,   DIG_N6DB,   DIG_N4DB,   DIG_N2DB,   DIG_N0DB,
};

#if DAC_SOFT_POW_CALC
AT(.com_text.dac)
bool soft_dac_pow_calc_en(void)
{
    return true;
}
#endif

AT(.text.bsp.dac)
void bsp_change_volume(u8 vol)
{
    printf("bsp_change_volume = %d\n",vol);
#if !SYS_ADJ_DIGVOL_EN
    ///sys adjust dac analog volume
    u8 anl_vol = 0;
    if (vol <= VOL_MAX) {
        if (vol > 0) {
            anl_vol = dac_avol_table[vol] + sys_cb.anl_gain_offset;
        }
		if(sys_cb.sco_start)
		{
			anl_vol+=SCO_VOL_OFFSET;
		}
		printf("anl vol:%d\n",anl_vol);
        dac_set_volume(anl_vol);
    }
#else
    ///sys adjust dac digital volume
    u16 dig_vol = 0;
    if (vol <= VOL_MAX) {
        dig_vol = dac_dvol_table[vol];
        dac_set_dvol(dig_vol);
    }
#endif
}

AT(.text.bsp.dac)
bool bsp_set_volume(u8 vol)
{
	printf("set vol:%d\n",vol);
    bsp_change_volume(vol);
    if (vol == sys_cb.vol) {
        gui_box_show_vol();
        return false;
    }

    if (vol <= VOL_MAX) {
        sys_cb.vol = vol;
        gui_box_show_vol();
        param_sys_vol_write();
        sys_cb.cm_times = 0;
        sys_cb.cm_vol_change = 1;
    }
    return true;
}

//左右音量平衡控制
AT(.text.bsp.aucar)
void bsp_aucar_set_bal_vol(u8 l_vol, u8 r_vol)
{
//    printf("bal_vol: %d, %d\n", l_vol, r_vol);
    dac_set_balance(aucar_bal_vol_table[l_vol], aucar_bal_vol_table[r_vol]);
}

//开机控制DAC电容放电等待时间
AT(.text.dac)
void dac_pull_down_delay(void)
{
    delay_5ms(DAC_PULL_DOWN_DELAY);
}

AT(.com_text.dac)
void dac_set_mute_callback(u8 mute_flag)
{
    if (mute_flag) {
        bsp_loudspeaker_mute();
    } else {
        if (!sys_cb.mute) {
            bsp_loudspeaker_unmute();
#if EARPHONE_DETECT_EN
            if (!dev_is_online(DEV_EARPHONE))
#endif
            {
                //DAC延时淡入，防止UNMUTE时间太短导致喇叭声音不全的问题
                dac_unmute_set_delay(LOUDSPEAKER_UNMUTE_DELAY);
            }
        }
    }
}

AT(.text.bsp.dac)
u8 bsp_volume_inc(u8 vol)
{
    vol++;
    if(vol > VOL_MAX)
        vol = VOL_MAX;
    return vol;
}

AT(.text.bsp.dac)
u8 bsp_volume_dec(u8 vol)
{
    if(vol > 0)
        vol--;
    return vol;
}

AT(.text.bsp.dac)
void dac_set_anl_offset(u8 bt_call_flag)
{
    if (bt_call_flag) {
        sys_cb.anl_gain_offset = 54 - 9 + BT_CALL_MAX_GAIN - dac_avol_table[VOL_MAX];
    } else {
        sys_cb.anl_gain_offset = 54 - 9 + DAC_MAX_GAIN - dac_avol_table[VOL_MAX];
    }
}

AT(.text.bsp.dac)
void dac_set_vol_table(u8 vol_max)
{
    if (vol_max == 16) {
        dac_avol_table = dac_vol_tbl_16;
        dac_dvol_table = dac_dvol_tbl_16;
    } else if (vol_max <= 32) {
        dac_avol_table = dac_vol_tbl_32;
        dac_dvol_table = dac_dvol_tbl_32;
    } else {
        dac_avol_table = dac_vol_tbl_50;
        dac_dvol_table = dac_dvol_tbl_50;
    }
    dac_set_anl_offset(0);
}

//dacr_not_poweron 使用场景：如DACR和PF3绑定在一起
//若此函数返回1, DACR在DAC初始化时进入低驱动状态，此时该绑定引脚电平可由PF3决定
//AT(.text.dac)
//u8 dacr_not_poweron(void)
//{
//    return 1;
//}

AT(.text.bsp.dac)
void amp_speaker_mute(void)
{
    if(sys_cb.amp_mute)
    {
    	return;
    }
	printf("amp mute!!\n");
	sys_cb.amp_mute=1;
	bsp_change_volume(0);
	delay_ms(5);
	AMPLIFIER_SEL_EXIT();
	delay_ms(5);
	bsp_change_volume(sys_cb.vol);
}
AT(.text.bsp.dac)
void amp_speaker_unmute(void)
{
    if(!sys_cb.amp_mute)
    {
    	return;
    }
	printf("amp unmute!!\n");
	sys_cb.amp_mute=0;
	bsp_change_volume(0);
	delay_ms(5);
	AMPLIFIER_SEL_D();
	delay_ms(5);
	bsp_change_volume(sys_cb.vol);
}

AT(.text.bsp.dac)
void dac_init(void)
{
    dac_set_vol_table(xcfg_cb.vol_max);
    printf("[%s] vol_max:%d, offset: %d\n", __func__, xcfg_cb.vol_max, sys_cb.anl_gain_offset);

    dac_obuf_init();
    dac_power_on();

#if (DAC_OUT_SPR == DAC_OUT_48K)
    DACDIGCON0 |= BIT(1);           //dac out sample 48K
#endif
    dac_digital_enable();

    plugin_music_eq();

#if SYS_ADJ_DIGVOL_EN
    dac_set_volume(54);             //analog volume设置0DB
#endif // SYS_ADJ_DIGVOL_EN

#if DAC_DNR_EN
    dac_dnr_init(2, 20, 88, 12);  //能量值连续超过2次大于20就认为有声，连续超过88次低于 12 就认为无声  //第二个参数需要大于第四个参数
#endif

#if DAC_DRC_EN || DAC_SOFT_EQ_EN
    #ifdef RES_BUF_EQ_NORMAL_EQ
    drc_cfg.eq_coef = (u8*)RES_BUF_EQ_NORMAL_EQ;
    #endif
    #ifdef RES_BUF_DRC_NORMAL_DRC
    drc_cfg.drc_coef = (u8*)RES_BUF_DRC_NORMAL_DRC;
    #endif
    dac_drc_init(&drc_cfg);

//    bool drc3_init(const void *bin, int bin_size, u8 drc_cb_i);  //DRC_V3 TEST
//    u8 *drc3_addr = (u8*)RES_BUF_DRC_NORMAL3_DRC;
//    u32 drc3_len = RES_LEN_DRC_NORMAL3_DRC;
//    drc3_init(drc3_addr, drc3_len, 0);
//    drc3_init(drc3_addr, drc3_len, 1);

#endif
    //dac_soft_diff_mono_mix();  //DAC软件差分单声道输出，DACR和DACL输出差分单声道信号
}

#if FFT_OUT_EN
extern u32 dac_obuf[576 + 512];
void fft_forward(s32 *buf);
s32 fft_mod_complex_s(s32 re, s32 im);
s32 fft_output[128] AT(.com_text.bb);
//--------------//
//fft_output是FFT输出数组，输出有效数据个数是60个，其他数据无效。
//fre写1，输出fft频谱范围0-20K，写2，输出fft频谱范围是0-10k。
//--------//
AT(.com_text.bb.cvsd)
void fft_mod_output(s32 *fft_buf, u8 fre)
{
    int i;
    for (i = 0; i < 128; i++) {
        fft_buf[i] = ((dac_obuf[fre*i])>>6);
    }

    fft_forward(fft_buf);
    for(i = 0; i < 64; i++) {
        fft_buf[i] = ((u32)fft_mod_complex_s(fft_buf[2*i], fft_buf[2*i + 1])) >> 20;    //计算复数的模
    }
}
//---------//
//对DAC输出进行FFT变换，得到各频率对应的能量值
//fre写1，输出fft频谱范围0-20K，写2，输出fft频谱范围是0-10k。
//eg:fre=1;输出1,2,3,4,5,6,7,8,9,10......59，60。
//则1,2,3为1k的频率对应的能量值，4,5,6,为2k对应的能量值
//------------//
/*
        get_fft实例：

        s32 *fft;
        fft = fft_output;
        fft_mod_output(fft,1);
        printf("\n->\n");
        for(int i=0; i< 64; i++) {
            printf("%d ",fft_output[i]);
        }
        memset(fft_output, 0, 128*4);
        printf("\n sys_cb.vol=%d\n",sys_cb.vol);
*/
//---------//
#endif

#if DAC_PCM_RM_VOICE_EN
static u8 rm_voice_en = 0;

void voice_rm_enable(void)
{
    rm_voice_en = 1;
}
void voice_rm_disable(void)
{
    rm_voice_en = 0;
}

AT(.com_text.pcm_ext)
bool dac_pcm_ext_en(void){ return true;}

AT(.com_text.pcm_ext)
void dac_pcm_ext_stereo(s16 *ldata, s16 *rdata)
{
    if(rm_voice_en)
    {
        dac_rm_voice_stereo(ldata, rdata);
    }
}

AT(.com_text.pcm_ext)
void dac_pcm_ext_mono(s16 *data)
{
    if(rm_voice_en)
    {
        dac_rm_voice_mono(data);
    }
}
#endif // DAC_PCM_RM_VOICE_EN
